// fileName      :  utils.go
// createdAt     :  2021-10-10
// description   :

package utils

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"go.uber.org/zap"
	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
	"log"
	"os"
	"reflect"
	"zl-gin/utils/snowflake"
)

var GlobalTrace *Tracer

// HashAndSalt 加密密码
func HashAndSalt(pwd []byte) string {
	hash, err := bcrypt.GenerateFromPassword(pwd, bcrypt.MinCost)
	if err != nil {
		return ""
		zap.L().Error("密码加密失败", zap.Error(err))
	}
	return string(hash)
}

// ComparePasswords 验证密码
func ComparePasswords(hashedPwd string, plainPwd []byte) bool {
	byteHash := []byte(hashedPwd)

	err := bcrypt.CompareHashAndPassword(byteHash, plainPwd)
	if err != nil {
		zap.L().Error("密码解密失败", zap.Error(err))
		return false
	}
	return true
}

//GetSnowFlakeId 利用雪花算法，生成唯一ID
func GetSnowFlakeId(idNode int64) (string, error) {
	node, err := snowflake.NewNode(idNode)
	if err != nil {
		return "", err
	}
	return node.Generate().String(), nil
}

/**
BuildQuery使用方法：
db := mysql.GetDbInstance()
	filter := map[string]interface{}{
		"id":         "123",
		"status":     []string{"1", "2"},
		"title":      "test",
		"is_default": 1,
	}
	extractField := []string{"status", "id", "is_default"}
	db = utils.BuildQuery(filter, extractField, db)
	db = db.Find(models.UserResult{})
*/

//构建查询条件
func BuildQuery(data map[string]interface{}, extractField []string, db *gorm.DB) *gorm.DB {
	if data == nil {
		return db
	}

	var whereRaw string
	var vals = make([]interface{}, len(data))
	var con string
	index := 0
	for _, key := range extractField {

		value, ok := data[key]
		if !ok {
			continue
		}
		valueType := reflect.ValueOf(value).Kind().String()
		if valueType == "slice" || valueType == "array" {
			whereRaw += con + key + " in(?) "
		} else {
			whereRaw += con + key + "=?"
		}
		vals[index] = value
		index++
		delete(data, key)
		con = " and "
	}

	if whereRaw == "" {
		con = ""
	}

	for key, val := range data {
		whereRaw += con + key + " like ?"
		vals[index] = "%" + fmt.Sprintf("%s", val) + "%"
		index++
	}

	db = db.Where(whereRaw, vals...)
	return db
}

func GetTracer(c *gin.Context) {
	tracer, _ := c.Get("trace")
	GlobalTrace = tracer.(*Tracer)
}

func GetEnv(env string) string {
	switch env {
	case "dev", "DEV":
		return "dev"

	case "SIT", "sit":
		return "sit"

	case "PRE", "pre":
		return "pre"

	case "PRD", "prd":
		return "prd"

	case "TEST", "test":
		return "test"

	default:
		return "dev"
	}
}

func GetGinMod(env string) string {
	_env := GetEnv(env)
	switch _env {
	case "test":
		return gin.TestMode
	case "prd":
		return gin.ReleaseMode
	default:
		return gin.DebugMode
	}
}

func CheckDirExistsAndMk(path string) {
	_, err := os.Stat(path) //os.Stat获取文件信息
	if err != nil {
		if !os.IsExist(err) {
			os.MkdirAll(path, 0777)
		}
	}
}

// GetExecDirectory 获取当前执行程序目录
func GetExecDirectory() string {
	file, err := os.Getwd()
	if err == nil {
		return file + "/"
	} else {
		log.Fatalln("GetExecDirectory err :", err)
	}
	return ""
}

func ZapLogInfo(format string, a ...interface{}) {
	err := fmt.Sprintf(format, a...)
	zap.L().Info(GlobalTrace.TraceId, zap.String("message", err))
}
func ZapLogDebug(format string, a ...interface{}) {
	err := fmt.Sprintf(format, a...)
	zap.L().Debug(GlobalTrace.TraceId, zap.String("message", err))
}

func ZapLogWarn(format string, a ...interface{}) {
	err := fmt.Sprintf(format, a...)
	zap.L().Warn(GlobalTrace.TraceId, zap.String("message", err))
}

func ZapLogError(format string, a ...interface{}) {
	err := fmt.Sprintf(format, a...)
	zap.L().Error(GlobalTrace.TraceId, zap.String("message", err))
}
